<template>
  <div>
    <canvas id="canvas" ref="canvas"></canvas>
    <button @click="play">play</button>
  </div>
</template>

<script>
import { AxesHelper, Color, Group, Matrix4, Mesh, MeshBasicMaterial, SphereGeometry, PerspectiveCamera, Euler, BoxGeometry, OrthographicCamera, Quaternion, DoubleSide,Scene, Vector3, WebGLRenderer, HemisphereLight, DirectionalLight } from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';

import { Joint } from '../three/Joint';


const map = {
  nose: null,
  left_eye_inner: null,
  left_eye: null,
  mixamorigLeftEye: null,
  left_eye_outer: null,
  right_eye_inner: null,
  right_eye: null,
  right_eye_outer: null,
  left_ear: null,
  right_ear: null,
  mouth_left: null,
  mouth_right: null,
  left_shoulder: "mixamorigLeftArm",
  left_elbow: "mixamorigLeftForeArm",
  left_wrist: "mixamorigLeftHand",
  right_shoulder: "mixamorigRightArm",
  right_elbow: "mixamorigRightForeArm",
  right_wrist: "mixamorigRightHand",
  left_pinky: null,
  right_pinky: null,
  left_index: null,
  right_index: null,
  left_thumb: null,
  right_thumb: null,
  left_hip: "mixamorigLeftUpLeg",
  left_knee: "mixamorigLeftLeg",
  left_ankle: "mixamorigLeftFoot",
  left_heel: "mixamorigLeftToeBase",
  right_hip: "mixamorigRightUpLeg",
  right_knee: "mixamorigRightLeg",
  right_ankle: "mixamorigRightFoot",
  right_heel: "mixamorigRightToeBase",
  left_foot_index: null,
  right_foot_index: null,
};

const mt4 = new Matrix4();

const mt4RotateZ = new Matrix4();
mt4RotateZ.makeRotationZ(Math.PI);

const mt4RotateY = new Matrix4();
mt4RotateY.makeRotationY(Math.PI / 2);

mt4.multiply(mt4RotateZ);
mt4.multiply(mt4RotateY);





export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data() {
    return {
      timer: null,
      renderer: null,
      camera: null,
      root: null,
      controls: null,
      metaData: null,
      index: 0

    }
  },

  methods: {
    play() {

      if (this.timer) {
        window.clearTimeout(this.timer)
        this.timer = null
        return
      }

    },

    render () {

    }
  },

  beforeDestroy () {
    window.cancelAnimationFrame(this.timer)
    this.renderer?.dispose()
    this.controls?.dispose()
    this.root?.dispose()
    this.camera?.dispose()
    this.renderer?.forceContextLoss()
    this.renderer?.forceContextLoss()
  },

  mounted() {


    this.root = new Scene();

    this.camera = new OrthographicCamera(-window.innerWidth / 2, window.innerWidth / 2, window.innerHeight / 2, -window.innerHeight / 2, 0.1, 1000);
    this.camera.position.set(300.076, 103.911, 0)

    this.renderer = new WebGLRenderer({ canvas: this.$refs.canvas, antialias: true });
    this.renderer.setSize(window.innerWidth, window.innerHeight);
    this.root.background = new Color(0, 0, 0);

    const hemiLight = new HemisphereLight(0xffffff, 0x8d8d8d, 3);
    hemiLight.position.set(0, 20, 0);
    this.root.add(hemiLight);

    const dirLight = new DirectionalLight(0xffffff, 3);
    dirLight.position.set(3, 10, 10);
    dirLight.castShadow = true;
    dirLight.shadow.camera.top = 2;
    dirLight.shadow.camera.bottom = - 2;
    dirLight.shadow.camera.left = - 2;
    dirLight.shadow.camera.right = 2;
    dirLight.shadow.camera.near = 0.1;
    dirLight.shadow.camera.far = 40;
    this.root.add(dirLight);

    this.controls = new OrbitControls(this.camera, this.renderer.domElement);


    const loader = new GLTFLoader();


    const tick = () => {
      this.timer = requestAnimationFrame(tick)
      this.controls.update()
      this.renderer.render(this.root, this.camera)
    }
    this.timer = requestAnimationFrame(tick)

    this.root.add(new AxesHelper(500));


    loader.load('/Xbot.glb', ({ scene }) => {
      scene.children[0].scale.set(1, 1, 1);




      this.root.add(scene)




      const leftLeg = ["left_hip", "left_knee", "left_ankle", "left_heel"];

      const leftLegJoint = new Joint(
        scene,
        leftLeg.map((v) => [map[v], v])
      );

      const rightLeg = ["right_hip", "right_knee", "right_ankle", "right_heel"];

      const rightLegJoint = new Joint(
        scene,
        rightLeg.map((v) => [map[v], v])
      );

      const angle = (Math.PI / 180) * 0;

      const baseAxies = new Vector3(1, 0, 0);

      const leftArm = ["left_shoulder", "left_elbow", "left_wrist"];
      const leftArmJoint = new Joint(
        scene,
        leftArm.map((v) => [map[v], v]),
        new Quaternion().setFromAxisAngle(baseAxies, -angle)
      );

      const rightArm = ["right_shoulder", "right_elbow", "right_wrist"];
      const rightArmJoint = new Joint(
        scene,
        rightArm.map((v) => [map[v], v]),
        new Quaternion().setFromAxisAngle(baseAxies, -angle)
      );

      scene.getObjectByName("mixamorigSpine").rotation.x = angle;




      Object.keys(map).forEach((v) => {
        if (!map[v]) {
          return
        }

        let color = 0xff0000

        if (leftLeg.includes(v)) {
          color = 0x00ff00
        }

        if (rightLeg.includes(v)) {
          color = 0x0000ff
        }

        if (leftArm.includes(v)) {
          color = 0x00ff00
        }

        if (rightArm.includes(v)) {
          color = 0x0000ff
        }

        const box = new Mesh(new BoxGeometry(4, 4, 4), new MeshBasicMaterial({ color: color, depthTest: false, side: DoubleSide }));
        box.name = v
        box.position.set(0, 0, 0);
        box.renderOrder = 9999;
        this.root.add(box);
      });





      const updatePose = (data) => {


        data.forEach(v => {
          const target = this.root.getObjectByName(v.name);
          if (target) {
            target.position.set(v.x, v.y, v.z);
          }
        })



        {
          const hip = data.find(v => v.name === "left_hip")

          const v3 = new Vector3(hip.x, 0, hip.z)

          const qu = new Quaternion()
          qu.setFromUnitVectors(new Vector3(1, 0, 0), v3.normalize())

          // scene.quaternion.copy(qu)
          // scene.getObjectByName("mixamorigLeftArm").quaternion.copy(qu)
          // scene.getObjectByName("mixamorigRightArm").quaternion.copy(qu)
          
        }

        {
          const l = data.find(v => v.name === "left_shoulder")
          const r = data.find(v => v.name === "right_shoulder")

          const v3l = new Vector3(l.x, l.y, l.z).normalize()
          const v3r = new Vector3(r.x, r.y, r.z).normalize()


          const v3 = new Vector3(l.x, 0, l.z).normalize()

          const qu = new Quaternion()
          qu.setFromUnitVectors(new Vector3(1, 0, 0), new Vector3(0.5, 0, 0.5))

          const qu2 = new Quaternion()
          qu2.setFromUnitVectors(new Vector3(0, 1, 0), new Vector3().addVectors(v3l, v3r).normalize())

          qu.multiply(qu2)

          scene.getObjectByName("mixamorigSpine").quaternion.copy(qu2)




          // const v3 = new Vector3().addVectors(
          //   new Vector3(l.x, l.y, l.z),
          //   new Vector3(r.x, r.y, r.z)
          // ).normalize()

          // const qu = new Quaternion()
          // qu.setFromUnitVectors(new Vector3(0, 1, 0), v3)

          // scene.getObjectByName("mixamorigSpine").quaternion.copy(qu)


        }



        {
          const state = {};
          leftLeg.forEach((v) => {
            const target = data.find((v2) => v2.name === v);
            if (target) {
              state[v] = {
                position: new Vector3(target.x, target.y, target.z),
                wight: target.score,
              };
            }
          });

          leftLegJoint.update(state);
        }

        {
          const state = {};
          rightLeg.forEach((v) => {
            const target = data.find((v2) => v2.name === v);
            if (target) {
              state[v] = {
                position: new Vector3(target.x, target.y, target.z),
                wight: target.score,
              };
            }
          });

          rightLegJoint.update(state);
        }

        {
          const state = {};
          leftArm.forEach((v) => {
            const target = data.find((v2) => v2.name === v);
            if (target) {
              state[v] = {
                position: new Vector3(target.x, target.y, target.z),
                wight: target.score,
              };
            }
          });

          leftArmJoint.update(state);
        }

        {
          const state = {};
          rightArm.forEach((v) => {
            const target = data.find((v2) => v2.name === v);
            if (target) {
              state[v] = {
                position: new Vector3(target.x, target.y, target.z),
                wight: target.score,
              };
            }
          });

          rightArmJoint.update(state);
        }
      }

      const loadMetaData = async () => {


        const metaData = await fetch("/dat3.json").then((res) => res.json());

        let index = 0;

        const loop = () => {
          this.timer = window.setTimeout(loop, 16);

          if (index < metaData.length) {

            

            // 217
            const state = metaData[index].map((v) => {

                const v3 = new Vector3(v.x * 100, v.y * 100, v.z * 100);
                v3.applyMatrix4(mt4);

                return {
                  ...v,
                  x: v3.x,
                  y: v3.y + 103.911,
                  z: v3.z + 2.076,
                };

              })


            updatePose(state);
          } else {
            window.clearTimeout(this.timer);
          }

          index++;
        };
        this.timer = window.setTimeout(loop, 1000 / 160);
      }

      loadMetaData();



    });

  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
div {
  position: relative;
}

canvas {
  width: 100vw;
  height: 100vh;
}

button {
  position: absolute;
  padding: 10px;
  left: 50%;
  transform: translateX(-50%);
  bottom: 100px;
  z-index: 10;
}

</style>
